package com.hb.trade.api.routine.controller.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import com.aliyun.oss.model.Bucket;
import com.aliyun.oss.model.ListObjectsV2Result;
import com.hb.core.pojo.Attachment;
import com.hb.core.pojo.Attachments;
import com.hb.core.pojo.center.sys.entity.FileRecord;
import com.hb.trade.client.center.FileClient;
import fzzn.core.aspose.convert.AsposeConvertUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.fzzn.core.cache.inmemory.InMemoryService;
import org.fzzn.core.file.base.FileBaseController;
import org.fzzn.core.file.entity.HbFileInfo;
import org.fzzn.core.file.entity.OssProperties;
import org.fzzn.core.file.entity.UploadEntity;
import org.fzzn.core.file.service.DownloadService;
import org.fzzn.core.file.service.PersistenceService;
import org.fzzn.core.model.constant.CommonConstant;
import org.fzzn.core.model.enums.MsgEnum;
import org.fzzn.core.model.msg.Message;
import org.fzzn.core.model.msg.ResponseDto;
import org.fzzn.core.service.ZipFileService;
import org.fzzn.core.util.IdUtil;
import org.fzzn.core.util.MsgUtil;
import org.fzzn.core.util.ResultUtil;
import org.fzzn.core.web.anno.Version;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

@RestController
@Slf4j
@Version(1.0)
@Api(tags = {"文件上传及管理接口"})
@RequestMapping("/{version}")
public class ApiFileController extends FileBaseController {

    protected final DownloadService downloadService;
    protected final InMemoryService memoryService;
    protected final FileClient fileClient;


    public ApiFileController(PersistenceService service,
                             DownloadService downloadService,
                             InMemoryService memoryService,
                             FileClient fileClient) {
        super(service);
        this.downloadService = downloadService;
        this.memoryService = memoryService;
        this.fileClient = fileClient;
    }

    /**
     * 文件上传接口
     *
     * @return
     */
    @ApiOperation(value = "文件上传接口", notes = "文件上传接口")
    @PostMapping("/file/upload/server")
    public ResponseDto<?> uploadServer(UploadEntity entity) {
        try {
            long beginTime = System.currentTimeMillis();
            List<HbFileInfo> fileInfos = persistenceService.uploadServer(entity);
            log.info("==总共消耗=="+(System.currentTimeMillis() - beginTime)+"ms");
            return ResultUtil.msg(true, fileInfos);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ResultUtil.FAIL;
    }

    /**
     * 查询OSS中容器名称
     *
     * @return
     */
    @ApiOperation(value = "查询OSS中容器名称", notes = "查询OSS中容器名称")
    @PostMapping("/file/bucketList")
    public ResponseDto<?> bucketList() {
        OssProperties properties = SpringUtil.getBean(OssProperties.class);
        List<Bucket> buckets = properties.getOssClient().listBuckets();
        return ResultUtil.msg(true, buckets);
    }

    /**
     * 查询OSS文件原文件中所有文件属性
     *
     * @param bucketName
     * @return
     */
    @ApiOperation(value = "获取OSS服务器的文件列表", notes = "获取OSS服务器的文件列表")
    @PostMapping("/file/bucket/fileList")
    public ResponseDto<?> fileList(String bucketName) {
        if (StrUtil.isEmpty(bucketName)) {
            return ResultUtil.fail("[bucketName]参数不能为空");
        }
        OssProperties properties = SpringUtil.getBean(OssProperties.class);
        ListObjectsV2Result objects = properties.getOssClient().listObjectsV2(bucketName);
        return ResultUtil.msg(true, objects);
    }

    /**
     * 获取OSS服务器上传密钥
     *
     * @return
     */
    @ApiOperation(value = "获取OSS服务器上传密钥", notes = "获取OSS服务器上传密钥")
    @GetMapping({"/file/oss/tradeStsToken"})
    public ResponseDto<?> tradeStsToken() {
        JSONObject object = stsToken();
        return ResultUtil.msg(true, object);
    }

    /**
     * 前端直传文件保存数据库
     *
     * @return
     */
    @ApiOperation(value = "前端直传文件保存数据库", notes = "前端直传文件保存数据库")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "文件ID, 不为空时为修改", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "dataTable", value = "业务表名", dataTypeClass = String.class),
            @ApiImplicitParam(name = "dataId", value = "业务表ID", dataTypeClass = String.class),
            @ApiImplicitParam(name = "fileSize", value = "文件大小", dataTypeClass = Long.class, required = true),
            @ApiImplicitParam(name = "fileName", value = "文件名(随机生成的唯一文件名)", dataTypeClass = String.class, required = true),
            @ApiImplicitParam(name = "rawFileName", value = "原文件名", dataTypeClass = String.class, required = true),
            @ApiImplicitParam(name = "extName", value = "文件扩展名", dataTypeClass = String.class, required = true),
            @ApiImplicitParam(name = "fileUrl", value = "文件保存的远程路径", dataTypeClass = String.class, required = true),
            @ApiImplicitParam(name = "filePath", value = "文件保存的本地路径", dataTypeClass = String.class),
            @ApiImplicitParam(name = "note", value = "备注", dataTypeClass = String.class)
    })
    @PostMapping({"/file/manage/persistence"})
    public ResponseDto<?> persistence(@RequestBody List<HbFileInfo> fileInfos) {
        boolean record = persistenceService.record(fileInfos);
        return ResultUtil.msg(record);
    }

    /**
     * 下载resources中template文件夹下的资源文件
     *
     * @param fileName 相对于resources/template文件夹下的相对路径
     * @param downName 下载时的文件名称
     * @return
     */
    @ApiOperation(value = "下载resources中template文件夹下的资源文件", notes = "下载resources中template文件夹下的资源文件", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fileName", value = "相对于resources/template文件夹下的相对路径", dataTypeClass = String.class),
            @ApiImplicitParam(name = "downName", value = "下载时的文件名称", dataTypeClass = String.class)
    })
    @PostMapping(value = "/file/resources/down")
    public void downloadResource(String fileName, String downName, HttpServletResponse response) {
        if (StrUtil.isEmpty(fileName)) {
            log.warn("文件路径不能为空");
            return;
        }
        if (StrUtil.isEmpty(downName)) {
            downName = FileUtil.getName(fileName);
        }
        if (fileName.startsWith("/")) {
            fileName = "template" + fileName;
        } else {
            fileName = "template/" + fileName;
        }
        downloadService.downloadResource(fileName, downName, response);
    }

    /**
     * 下载内存中保存的文件
     *
     * @param fileId 该参数为后端生成的字符串保存在redis里面的
     * @return
     * @update zhaojk
     */
    @ApiOperation(value = "下载内存中保存的文件", notes = "下载内存中保存的文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fileId", value = "招标文件临时ID, 后端提供", dataTypeClass = String.class)
    })
    @GetMapping("/file/memory/download")
    public void downloadFileByMemory(String fileId, HttpServletResponse response) {
        if (fileId == null) {
            log.warn(MsgEnum.INCORRECT_PARAM.msg());
            return;
        }
        String filePath = memoryService.get(fileId);
        if (StrUtil.isEmpty(filePath)) {
            log.error("文件不存在或者已经过期");
            return;
        }

        File file = new File(filePath);
        if (file.exists()) {
            downloadService.download(file.getName(), file, response);
        }

        // 删除文件(先不删除)
        // FileUtil.del(file);
    }

    /**
     * 将文件对象转换成PDF返回至前端
     *
     * @param fileInfos 文件对象
     * @update zhaojk
     */
    @ApiOperation(value = "将文件对象转换成PDF返回至前端", notes = "将文件对象转换成PDF返回至前端")
    @PostMapping("/file/word2PDF")
    public ResponseDto<?> fileWord2PDF(@RequestBody List<HbFileInfo> fileInfos) {
        Attachments attachments = Attachments.getInstance(fileInfos);
        List<HbFileInfo> hbFileInfos = CollUtil.list(false);
        for (Attachment attachment : attachments) {
            String extName = attachment.getExtName();
            // 只转换word文件
            if (!"doc".equals(extName) && !"docx".equals(extName)) {
                continue;
            }
            File thisFile = attachment.getThisFile();
            byte[] pdfBytes = AsposeConvertUtil.wordToPDF(thisFile);

            File pdfFile = new File(CommonConstant.TEMP_PATH + "/" + attachment.getRawFileName() + ".pdf");
            FileUtil.writeBytes(pdfBytes, pdfFile);

            // 将PDF文件上传至OSS
            UploadEntity entity = new UploadEntity(pdfFile);
            List<HbFileInfo> uploadFiles;
            try {
                uploadFiles = persistenceService.uploadServer(entity);
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
            hbFileInfos.addAll(uploadFiles);
        }
        return ResultUtil.msg(true, hbFileInfos);
    }

    /**
     * 下载指定ID的文件
     *
     * @param fileId
     * @return
     * @update zhaojk
     */
    @ApiOperation(value = "下载指定ID的文件", notes = "下载指定ID的文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fileId", value = "文件管理系统的ID值", dataTypeClass = String.class)
    })
    @RequestMapping("/file/id/download")
    public void downloadFileById(Long fileId, HttpServletResponse response) {
        List<HbFileInfo> fileInfos = persistenceService.listByIds(CollUtil.list(false, fileId));
        if (CollUtil.isEmpty(fileInfos)) {
            return;
        }
        HbFileInfo fileInfo = fileInfos.get(0);
        File file = fileInfo.getFile();
        downloadService.download(fileInfo.getRawFileName() + CommonConstant.COMMA + fileInfo.getExtName(),
                file, response);
    }

    /**
     * 下载指定名称的文件
     *
     * @param fileName
     * @return
     * @update zhaojk
     */
    @ApiOperation(value = "下载指定文件名称的文件", notes = "下载指定文件名称的文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fileName", value = "后端生成的随机的文件名称", dataTypeClass = String.class)
    })
    @RequestMapping("/file/name/download")
    public void downloadFileByName(String fileName, HttpServletResponse response) {
        List<HbFileInfo> fileInfos = persistenceService.listByFileNames(CollUtil.list(false, fileName));
        if (CollUtil.isEmpty(fileInfos)) {
            return;
        }
        HbFileInfo fileInfo = fileInfos.get(0);
        File file = fileInfo.getFile();
        downloadService.download(fileInfo.getRawFileName() + CommonConstant.COMMA + fileInfo.getExtName(),
                file, response);
    }

    /**
     * 打包下载指定ID的文件列表
     *
     * @param fileIds
     * @return
     * @update zhaojk
     */
    @ApiOperation(value = "打包下载指定ID的文件列表", notes = "打包下载指定ID的文件列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fileIds", value = "文件ID集合", dataTypeClass = String.class)
    })
    @RequestMapping("/file/ids/downzip")
    public void downloadFileZipByIds(@RequestBody List<Long> fileIds, HttpServletResponse response) {
        List<HbFileInfo> fileInfos = persistenceService.listByIds(fileIds);
        if (CollUtil.isEmpty(fileInfos)) {
            return;
        }
        // 取第一个文件名作为压缩包的名字
        String finalName = fileInfos.get(0).getRawFileName();

        // 构建压缩包文件, 并添加文件
        ZipFileService zipFileService = ZipFileService.getInstance();
        for (HbFileInfo fileInfo : fileInfos) {
            zipFileService.add(fileInfo.getRawFileName() + CommonConstant.COMMA + fileInfo.getExtName(), fileInfo.getFile());
        }

        // 生成下载文件
        File file = zipFileService.file(finalName + CommonConstant.COMMA + "zip");
        downloadService.download(file.getName(), file, response);
    }


    /**
     * 将oss文件保存至数据库
     *
     * @return
     */
    @ApiOperation(value = "将oss文件保存至数据", notes = "将oss文件保存至数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fileUrl", value = "OSS路径", dataTypeClass = String.class),
            @ApiImplicitParam(name = "rawFileName", value = "源文件名称", dataTypeClass = String.class)
    })
    @PostMapping({"/file/saveFileByFileUrl"})
    public ResponseDto<?> saveFileByFileUrl(@RequestBody FileRecord fileRecord) {
        if (StringUtils.isEmpty(fileRecord.getFileUrl()) || StringUtils.isEmpty(fileRecord.getRawFileName())) {
            return ResultUtil.fail(MsgEnum.INCORRECT_PARAM);
        }
        int index = fileRecord.getFileUrl().lastIndexOf(".");

        if (index != -1 && index != 0) {
            String[] split = fileRecord.getFileUrl().split("/");
            String[] fileName = split[split.length-1].split("\\.");
            fileRecord.setFileName(fileName[0]);
            fileRecord.setExtName(fileName[1]);
        }
        fileRecord.setFilePath(null); // 因为oss文件没有filePath 所以存空
        fileRecord.setId(IdUtil.getId());
        fileRecord.setCreateTime(LocalDateTime.now());
        fileRecord.setUpdateTime(LocalDateTime.now());
        Message<Boolean> record = fileClient.saveFile(fileRecord);
        if (record.isSuccess()) {
            return ResultUtil.msg(MsgUtil.success(fileRecord));
        }
        return ResultUtil.fail("入库失败");
    }
}
